/*
 * SignalInterfaces.h
 *
 *  Created on: 26.08.2008
 *      Author: karl wessel
 */

#ifndef SIGNALINTERFACES_H_
#define SIGNALINTERFACES_H_

#include "global/MiXiMDefs.h"
#include "MappingBase.h"

class FilledUpMapping;

/**
 * @brief This iterator takes another ConstMappingIterator and does
 * just pipe every method to the passed ConstMappingIterator.
 *
 * This class is meant to be used as base class for Iterators which
 * want to change just several parts without having to implement and pipe every
 * other method of the ConstMappingIteratorInterface.
 *
 * Note: Does take ownership of the passed iterator pointer!
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
template<class Base>
class BaseFilteredIterator : public Base
{
public:

    typedef typename Base::argument_value_t      argument_value_t;
    typedef typename Base::argument_value_cref_t argument_value_cref_t;

protected:

    Base* origIterator;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & origIterator;
    }

public:

    BaseFilteredIterator(Base* orig): origIterator(orig) {}

    virtual ~BaseFilteredIterator() { delete origIterator; }

    virtual const Argument& getNextPosition() const { return origIterator->getNextPosition(); }

    virtual void jumpTo(const Argument& pos) { origIterator->jumpTo(pos); }

    virtual void jumpToBegin() { origIterator->jumpToBegin(); }

    virtual void iterateTo(const Argument& pos) { origIterator->iterateTo(pos); }

    virtual void next() { origIterator->next(); }

    virtual bool inRange() const { return origIterator->inRange(); }

    virtual bool hasNext() const { return origIterator->hasNext(); }

    virtual const Argument& getPosition() const { return origIterator->getPosition(); }

    virtual argument_value_t getValue() const { return origIterator->getValue(); }
};


/**
 * @brief Const version of the BaseFilteredIterator. Meant to be used for
 * ConstMappingIterator instances.
 *
 * @sa BaseFilteredIterator *
 * @author Karl Wessel
 * @ingroup mappingDetails
 * */
typedef BaseFilteredIterator<ConstMappingIterator> FilteredConstMappingIterator;

/**
 * @brief Non-Const version of the BaseFilteredIterator. Meant to be used for
 * MappingIterator instances.
 *
 * @sa BaseFilteredIterator
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
class MIXIM_API FilteredMappingIterator : public BaseFilteredIterator<MappingIterator>
{
public:

    FilteredMappingIterator(MappingIterator* orig): BaseFilteredIterator<MappingIterator>(orig) {}

    virtual ~FilteredMappingIterator() {}

    virtual void setValue(argument_value_cref_t value) { origIterator->setValue(value); }
};


/**
 * @brief Provides an implementation of the MappingIterator-
 * Interface which is able to iterate over TimeMappings.
 *
 * @author Karl Wessel
 * @ingroup mapping
 */
template<template <typename> class Interpolator>
class TimeMappingIterator:public MappingIterator
{
protected:

    /** @brief The templated InterpolateableMap the underlying Mapping uses std::map as storage type.*/
    typedef InterpolateableMap< Interpolator< std::map<omnetpp::simtime_t, argument_value_t> > > interpolator_map_type;
    typedef typename interpolator_map_type::interpolator_type    interpolator_type;
    typedef typename interpolator_map_type::mapped_type          mapped_type;
    typedef typename interpolator_map_type::iterator_intpl       iterator;
    typedef typename interpolator_map_type::const_iterator_intpl const_iterator;

    /** @brief Stores the current position iterator inside the Mapping.*/
    iterator     valueIt;

    /** @brief Stores the current position of the iterator.*/
    Argument     position;

    /** @brief Stores the next position a call of "next()" would jump to.*/
    Argument     nextPosition;

    /**
     * @brief Stores if this mapping represents a step function.
     *
     * Assures that the steps are considered when iterating the mapping
     * by adding a second key-entry as short as possible before every
     * key entry set by the user. The additional key-entry defines the
     * value the mapping has just before the key entry the user added.
     */
    bool         isStepMapping;

    bool         atPreStep;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & valueIt;
        archive & position;
        archive & nextPosition;
        archive & isStepMapping;
        archive & atPreStep;
    }

protected:

    void updateNextPos()
    {
        omnetpp::simtime_t t = valueIt.getNextPosition();

        if(isStepMapping && !atPreStep)
            t.setRaw(t.raw() - 1);

        nextPosition.setTime(t);
    }

public:

    /**
     * @brief Initializes the Iterator to use the passed InterpolateableMapIterator.
     */
    TimeMappingIterator(const iterator& it):
        valueIt(it), isStepMapping(it.getInterpolator().isStepping()), atPreStep(false) {
        interpolator_type UsedInterpolator;

        isStepMapping = UsedInterpolator.isStepping();
        position.setTime(valueIt.getPosition());
        updateNextPos();
    }

    /**
     * @brief Lets the iterator point to the passed position.
     *
     * The passed new position can be at arbitrary places.
     *
     * This method has logarithmic complexity.
     */
    void jumpTo(const Argument& pos) {
        atPreStep = false;
        valueIt.jumpTo(pos.getTime());
        position.setTime(pos.getTime());
        nextPosition.setTime(valueIt.getNextPosition());
    }

    /**
     * @brief Iterates to the specified position. This method
     * should be used if the new position is near the current position.
     *
     * The passed position should compared bigger than the current position.
     *
     * This method has linear complexity over the number of key-entries
     * between the current position and the passed position. So if the
     * passed position is near the current position the complexity is
     * nearly constant.
     */
    void iterateTo(const Argument& pos) {
        atPreStep = false;
        valueIt.iterateTo(pos.getTime());
        position.setTime(pos.getTime());
        nextPosition.setTime(valueIt.getNextPosition());
    }

    /**
     * @brief Iterates to the next position of the function.
     *
     * The next position is the next bigger key entry of the
     * InterpoalteableMap.
     *
     * This method has constant complexity.
     */
    virtual void next() {
        if(isStepMapping && !atPreStep){
            valueIt.iterateTo(nextPosition.getTime());
            atPreStep = true;
        } else {
            valueIt.next();
            atPreStep = false;
        }
        position.setTime(valueIt.getPosition());
        updateNextPos();
    }

    /**
     * @brief Returns true if the current position of the iterator
     * is in range of the function.
     *
     * This method should be used as end-condition when iterating
     * over the function with the "next()" method.
     *
     * THis method has constant complexity.
     */
    virtual bool inRange() const {
        return valueIt.inRange();
    }

    /**
     * @brief Returns the current position of the iterator.
     *
     * This method has constant complexity.
     */
    virtual const Argument& getPosition() const {
        return position;
    }

    /**
     * @brief Returns the next position a call to "next()" would jump to.
     *
     * This method has constant complexity.
     */
    virtual const Argument& getNextPosition() const {
        return nextPosition;
    }

    /**
     * @brief Returns the value of the function at the current
     * position.
     *
     * This method has constant complexity.
     */
    virtual mapped_type getValue() const {
        return *valueIt.getValue();
    }

    /**
     * @brief Lets the iterator point to the begin of the mapping.
     *
     * The beginning of the mapping is the smallest key entry in the
     * InterpolateableMap.
     *
     * Constant complexity.
     */
    virtual void jumpToBegin() {
        valueIt.jumpToBegin();
        position.setTime(valueIt.getPosition());
    }

    /**
     * @brief Returns true if the iterator has a next value
     * inside its range a call to "next()" can jump to.
     *
     * Constant complexity.
     */
    virtual bool hasNext() const {
        return valueIt.hasNext();
    }

    /**
     * @brief Changes the value of the function at the current
     * position.
     *
     * This method has constant complexity.
     */
    virtual void setValue(argument_value_cref_t value) {
        valueIt.setValue(value);
    }
};


/**
 * @brief Implements the Mapping-interface with an InterpolateableMap from
 * simtime_t to double between which values can be interpolated to represent
 * a Mapping with only time as domain.
 *
 * @author Karl Wessel
 * @ingroup mapping
 */
template<template <typename> class Interpolator>
class TimeMapping:public Mapping
{
protected:

    /** @brief The templated InterpolateableMap the underlying Mapping uses std::map as storage type.*/
    typedef InterpolateableMap< Interpolator< std::map<omnetpp::simtime_t, argument_value_t> > > interpolator_map_type;
    typedef typename interpolator_map_type::interpolator_type    interpolator_type;
    typedef typename interpolator_map_type::mapped_type          mapped_type;
    typedef typename interpolator_map_type::mapped_cref_type     mapped_cref_type;
    typedef typename interpolator_map_type::iterator_intpl       iterator;
    typedef typename interpolator_map_type::const_iterator_intpl const_iterator;

    /** @brief Stores the key-entries defining the function.*/
    interpolator_map_type entries;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & entries;
    }

public:

    /**
     * @brief Initializes the Mapping with the passed Interpolation method.
     */
    TimeMapping():
        Mapping(), entries() {}

    /**
     * @brief Initializes the Mapping with the passed Interpolation method.
     */
    TimeMapping(mapped_cref_type outOfRangeVal):
        Mapping(), entries(outOfRangeVal) {}

    /**
     * @brief returns a deep copy of this mapping instance.
     */
    virtual Mapping* clone() const { return new TimeMapping<Interpolator>(*this); }

    /**
     * @brief Returns the value of this Function at the position specified
     * by the passed Argument.
     *
     * This method has logarithmic complexity.
     */
    virtual argument_value_t getValue(const Argument& pos) const {
        return *entries.getIntplValue(pos.getTime());
    }

    /**
     * @brief Changes the value of the function at the specified
     * position.
     *
     * This method has logarithmic complexity.
     */
    virtual void setValue(const Argument& pos, argument_value_cref_t value) {
        entries[pos.getTime()] = value;
    }

    /**
     * @brief Returns a pointer of a new Iterator which is able to iterate
     * over the function and can change the value the iterator points to.
     *
     * Note: The caller of this method has to delete the returned Iterator
     * pointer if it isn't used anymore.
     */
    virtual MappingIterator* createIterator() {
        return new TimeMappingIterator<Interpolator>(entries.beginIntpl());
    }

    /**
     * @brief Returns a pointer of a new Iterator which is able to iterate
     * over the function and can change the value the iterator points to.
     *
     * Note: The caller of this method has to delete the returned Iterator
     * pointer if it isn't used anymore.
     */
    virtual MappingIterator* createIterator(const Argument& pos) {
        return new TimeMappingIterator<Interpolator>(entries.findIntpl(pos.getTime()));
    }
};


/**
 * @brief Helper-class for the MultiDimMapping which provides an Iterator
 * which linear interpolates between two other Mapping iterators. Or in
 * other words, it provides an Iterator for an linear interpolated Mapping.
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
class MIXIM_API LinearIntplMappingIterator:public MappingIterator
{
protected:

    /** @brief Iterator for the left Mapping to interpolate.*/
    ConstMappingIterator* leftIt;
    /** @brief Iterator for the right Mapping to interpolate.*/
    ConstMappingIterator* rightIt;

    /** @brief The factor defining how strong the left and the right Mapping
     * affect the interpolation.*/
    argument_value_t      factor;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & leftIt;
        archive & rightIt;
        archive & factor;
    }

public:
    /**
     * @brief Initializes the Iterator with the passed Iterators of the mappings to
     * Interpolate and the their interpolation-factor.
     */
    LinearIntplMappingIterator(ConstMappingIterator* leftIt, ConstMappingIterator* rightIt, argument_value_cref_t f);

    /**
     * @brief Deletes the left and the right mapping iterator.
     */
    virtual ~LinearIntplMappingIterator();

    /**
     * @brief An interpolated mapping isn't really iterateable over specific
     * values, it only provides an fast way to get several values from an
     * Interpolated mapping.
     */
    virtual bool hasNext() const { return false; }
    /**
     * @brief An interpolated mapping isn't really iterateable over specific
     * values, it only provides an fast way to get several values from an
     * Interpolated mapping.
     */
    virtual bool inRange() const { return false; }

    /**
     * @brief This method isn't supported by an interpolated Mapping.
     */
    virtual void jumpToBegin() { assert(false); }
    /**
     * @brief This method isn't supported by an interpolated Mapping.
     */
    virtual void next() { assert(false); }

    /**
     * @brief This method isn't supported by an interpolated Mapping.
     */
    virtual void setValue(argument_value_cref_t value) { assert(false); }

    /**
     * @brief Lets the iterator point to the passed position.
     *
     * This method has logarithmic complexity over both of the
     * underlying Mappings used to interpolate.
     */
    virtual void jumpTo(const Argument& pos){
        leftIt->jumpTo(pos);
        rightIt->jumpTo(pos);
    }

    /**
     * @brief Increases the iterator to the passed position. This
     * position should be near the current position of the iterator.
     *
     * The passed position has to be compared bigger than the current position.
     *
     * This method has linear complexity over the number of key entries between
     * the current and the passed position in both underlying mappings used to
     * interpolate. So if the passed position is near the current position this
     * method has nearly constant complexity.
     */
    virtual void iterateTo(const Argument& pos){
        leftIt->iterateTo(pos);
        rightIt->iterateTo(pos);
    }

    /**
     * @brief Returns the value of the Interpolated mapping at the current
     * position of the iterator.
     *
     * This method has constant complexity.
     */
    virtual argument_value_t getValue() const {
        argument_value_cref_t v0 = leftIt->getValue();
        argument_value_cref_t v1 = rightIt->getValue();
        return v0 + (v1 - v0) * factor;
    }

    /**
     * @brief Returns the current position of the iterator.
     *
     * Constant complexity.
     */
    virtual const Argument& getPosition() const {
        return leftIt->getPosition();
    }

    /**
     * @brief This method isn't supported by an interpolated mapping.
     */
    virtual const Argument& getNextPosition() const { assert(false); return *((Argument *)NULL); }
};


/**
 * @brief Helper class which represents a linear interpolation between
 * two other mappings.
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
class MIXIM_API LinearIntplMapping:public Mapping
{
protected:

    /** @brief The left mapping to interpolate.*/
    const ConstMapping* left;
    /** @brief The right mapping to interpolate*/
    const ConstMapping* right;

    /** @brief The interpolation factor determining the linear interpolation
     * between left and right mapping.*/
    argument_value_t    factor;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & left;
        archive & right;
        archive & factor;
    }

public:

    /**
     * @brief Initializes the LinearIntplMapping with the passed left and right
     * Mapping to interpolate by the passed interpolation value.
     */
    LinearIntplMapping(const ConstMapping *const left = NULL, const ConstMapping *const right = NULL, argument_value_cref_t f = Argument::MappedZero()):
        left(left), right(right), factor(f) {}

    /**
     * @brief Interpolated mappings are not supposed to be cloned!
     */
    virtual Mapping* clone() const{ assert(false); return 0; }

    /**
     * @brief Returns the linear interpolated value of this Mapping.
     *
     * The value is calculated by the following formula:
     *
     * v = left + (right - left) * intplFactor
     */
    virtual argument_value_t getValue(const Argument& pos) const {
        assert(left);
        assert(right);

        argument_value_cref_t v0 = left->getValue(pos);
        argument_value_cref_t v1 = right->getValue(pos);
        //return v0 + (v1 - v0) * factor;
        return v0 * (Argument::MappedOne() - factor) + v1 * factor;
    }

    /**
     * @brief An interpolated mapping doesn't have a valid "first"-entry,
     * so this method is not supported.
     */
    virtual MappingIterator* createIterator() {
        assert(false);
        return 0;
    }

    /**
     * @brief Creates an iterator for this mapping starting at
     * the passed position.
     *
     * Note: The returned Iterator does only support a subset of the
     * normal MappingIterator-methods. See LinearIntplMappingIterator for
     * details.
     */
    virtual MappingIterator* createIterator(const Argument& pos) {
        assert(left);
        assert(right);

        return new LinearIntplMappingIterator(left->createConstIterator(pos), right->createConstIterator(pos), factor);
    }

    /**
     * @brief This method is not supported!
     */
    virtual void setValue(const Argument& pos, argument_value_cref_t value) { assert(false); }
};


/**
 * @brief Helper class (-specialization) for multiDimMapping which is used by an
 * InterpolateableMap as return value of the "getValue()" - method.
 *
 * Provides either an pointer to an actual SubMapping of the MultiDimMapping or
 * a Pointer to an temporary InterpolatedMapping between two Sub-mappings of the
 * MultiDimMapping.
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
template<>
class Interpolated<Mapping*>
{
protected:

    typedef Mapping*          value_type;
    typedef const value_type& value_cref_type;
    typedef value_type&       value_ref_type;
    typedef value_type*       value_ptr_type;

    /** @brief Holds the temporary InterpolatedMapping if necessary.*/
    LinearIntplMapping mapping;

    /** @brief A pointer to the Mapping this class represents.*/
    value_type value;

    /** @brief Stores if we use the temporary IntplMapping or a external pointer.*/
    bool       isPointer;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & mapping;
        archive & value;
        archive & isPointer;
        archive & isInterpolated;
    }

public:

    /** @brief Stores if the underlying Mapping is interpolated or not.*/
    bool       isInterpolated;

public:

    /**
     * @brief Initializes this Interpolated instance to represent the passed
     * Interpolated Mapping. Copies the passed Mapping to its internal member.
     * Sets "isInterpolated" to true.
     */
    Interpolated(const LinearIntplMapping& m):
        mapping(m), isPointer(false), isInterpolated(true) {

        value = &mapping;
    }

    /**
     * @brief Initializes this Interpolated instance to represent the Mapping
     * the passed pointer points to and with the passed isIntpl value.
     *
     * The passed pointer has to be valid as long as this instance exists.
     */
    Interpolated(value_type v, bool isIntpl = true):
        mapping(), value(v), isPointer(true), isInterpolated(isIntpl) {}

    /**
     * @brief Copy-constructor which assures that the internal storage is used correctly.
     */
    Interpolated(const Interpolated<value_type>& o):
        mapping(), value(o.value), isPointer(o.isPointer), isInterpolated(o.isInterpolated) {
        if(!isPointer) {
            mapping = o.mapping;
            value = &mapping;
        }
    }

    /**
     * @brief Assignment operator which assures that the internal storage is copied
     * correctly.
     */
    const Interpolated<value_type>& operator=(const Interpolated<value_type>& o){
        isInterpolated = o.isInterpolated;
        isPointer      = o.isPointer;
        value          = o.value;
        if(!isPointer) {
            mapping = o.mapping;
            value   = &mapping;
        }
        return *this;
    }

    /**
     * @brief Dereferences this Interpolated to the represented value (works like
     * dereferencing an std::iterator).
     */
    value_ref_type operator*() {
        return value;
    }

    /**
     * @brief Dereferences this Interpolated to the represented value (works like
     * dereferencing an std::iterator).
     */
    value_ptr_type operator->() {
        return &value;
    }

    /**
     * @brief Two Interpolated<Mapping*> are compared equal if the pointer to
     * the represented Mapping is the same as well as the "isInterpolated"
     * value.
     */
    bool operator==(const Interpolated<value_type>& other) const {
        return value == other.value && isInterpolated == other.isInterpolated;
    }

    /**
     * @brief Two Interpolated<Mapping*> are compared non equal if the pointer to
     * the represented Mapping differs or the "isInterpolated"
     * value.
     */
    bool operator!=(const Interpolated<value_type>& other) const {
        return value != other.value || isInterpolated != other.isInterpolated;
    }
};


/**
 * @brief Specialization of the Linear-template which provides LinearInterpolation
 * for pointer two Mappings. Used by MultiDimMapping.
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
template<>
class Linear< std::map<Argument::mapped_type, Mapping*> > : public InterpolatorBase< std::map<Argument::mapped_type, Mapping*> >
{
protected:

    typedef InterpolatorBase< std::map<Argument::mapped_type, Mapping*> > base_class_type;

public:

    typedef base_class_type::storage_type     storage_type;
    typedef base_class_type::container_type   container_type;
    typedef base_class_type::key_type         key_type;
    typedef base_class_type::key_cref_type    key_cref_type;
    typedef base_class_type::mapped_type      mapped_type;
    typedef base_class_type::mapped_cref_type mapped_cref_type;
    typedef base_class_type::pair_type        pair_type;
    typedef base_class_type::iterator         iterator;
    typedef base_class_type::const_iterator   const_iterator;
    typedef base_class_type::comparator_type  comparator_type;
    typedef base_class_type::interpolated     interpolated;

public:

    Linear():
        base_class_type() {}

    Linear(mapped_cref_type oorv):
        base_class_type(oorv) {}

    virtual ~Linear() {}

    /**
     * @brief Functor operator of this class which linear interpolates the value
     * at the passed position using the values between the passed Iterators.
     *
     * The upperBound-iterator has to point two the entry next bigger as the
     * passed position to interpolate.
     *
     * The returned instance of interpolated represents the result. Which can be
     * either an actual entry of the interpolated map (if the position two
     * interpolate was exactly that. Or it can be an interpolated value, if the
     * passed position was between two entries of the map.
     * This state can be retrieved with the "isInterpolated"-Member of the returned
     * "interpolated".
     */
    virtual interpolated operator()(const const_iterator&  first,
            const const_iterator&  last,
            key_cref_type          pos,
            const_iterator         upperBound) const
    {
        if(first == last)
            return base_class_type::outOfRangeVal;


        if(upperBound == first)
            return asInterpolated(upperBound->second, true);


        const_iterator right = upperBound;
        const_iterator left  = --upperBound;

        if(left->first == pos)
            return asInterpolated(left->second, false, false);

        if(right == last)
            return asInterpolated(left->second, true);


        return interpolated(LinearIntplMapping(left->second, right->second, linearInterpolationFactor(pos, left->first, right->first)));
    }

protected:

    /**
     * @brief calculates the linear interpolation factor used for the created
     * LinearIntplMappings.
     */
    static ConstMapping::argument_value_t linearInterpolationFactor(key_cref_type t, key_cref_type t0, key_cref_type t1)
    {
        assert( (t0 <= t && t <= t1) || (t0 >= t && t >= t1) );
        if (t0 == t1)
            return 0;

        return cast_it<ConstMapping::argument_value_t>( (t - t0) / (t1 - t0) );
    }
};


/**
 * @brief Represents a constant mathematical mapping (f(x) = c)
 *
 * Returns the same value for every point in any dimension.
 *
 * @author Karl Wessel
 * @ingroup mapping
 */
class MIXIM_API ConstantSimpleConstMapping : public SimpleConstMapping
{
protected:

    argument_value_t value;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & value;
    }

public:

    ConstantSimpleConstMapping(const DimensionSet& dims, argument_value_cref_t val):
        SimpleConstMapping(dims), value(val) {}

    ConstantSimpleConstMapping(const DimensionSet&   dims,
            const Argument&       key,
            argument_value_cref_t val):
                SimpleConstMapping(dims, key), value(val) {}

    virtual argument_value_t getValue(const Argument& pos) const {
        return value;
    }

    /**
     * @brief Returns the value of this constant mapping.
     */
    const argument_value_t getValue() const {
        return value;
    }

    /**
     * @brief Sets the value of this constant mapping.
     */
    void setValue(argument_value_cref_t val) { value = val; }

    ConstMapping* constClone() const  {
        return new ConstantSimpleConstMapping(dimensions, value);
    }
};


/**
 * @brief Wraps an ConstMappingIterator into a MappingIterator
 * interface.
 *
 * Assumes that "setValue()" of the MappingIterator interface will
 * never be called.
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
class MIXIM_API ConstMappingIteratorWrapper : public MappingIterator
{
protected:

    ConstMappingIterator *const iterator;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & iterator;
    }

public:

    ConstMappingIteratorWrapper(ConstMappingIterator* it):
        iterator(it) {}

    virtual ~ConstMappingIteratorWrapper()
    {
        if(iterator)
            delete iterator;
    }

    virtual void setValue(argument_value_cref_t value) { assert(false); }

    virtual const Argument& getNextPosition() const { return iterator->getNextPosition(); }

    virtual void jumpTo(const Argument& pos) { iterator->jumpTo(pos); }

    virtual void jumpToBegin() { iterator->jumpToBegin(); }

    virtual void iterateTo(const Argument& pos) { iterator->iterateTo(pos); }

    virtual void next() { iterator->next(); }

    virtual bool inRange() const { return iterator->inRange(); }

    virtual bool hasNext() const { return iterator->hasNext(); }

    virtual const Argument& getPosition() const { return iterator->getPosition(); }

    virtual argument_value_t getValue() const { return iterator->getValue(); }
};


/**
 * @brief Wraps an ConstMapping into a Mapping interface.
 *
 * Assumes that "setValue()" of the Mapping interface will
 * never be called.
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
class MIXIM_API ConstMappingWrapper : public Mapping
{
protected:

    const ConstMapping* mapping;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & mapping;
    }

public:

    ConstMappingWrapper(const ConstMapping* m):
        Mapping(m->getDimensionSet()), mapping(m) {}

    virtual void setValue(const Argument& pos, argument_value_cref_t value) { assert(false); }

    virtual MappingIterator* createIterator() {
        return new ConstMappingIteratorWrapper(mapping->createConstIterator());
    }

    virtual MappingIterator* createIterator(const Argument& pos) {
        return new ConstMappingIteratorWrapper(mapping->createConstIterator(pos));
    }

    virtual argument_value_t getValue(const Argument& pos) const { return mapping->getValue(pos); }

    virtual ConstMappingIterator* createConstIterator() const {
        return mapping->createConstIterator();
    }

    virtual ConstMappingIterator* createConstIterator(const Argument& pos) const {
        return mapping->createConstIterator(pos);
    }

    virtual ConstMapping* constClone() const { return mapping->constClone(); }

    virtual Mapping* clone() const {
        return new ConstMappingWrapper(mapping->constClone());
    }
};


template<template <typename> class Interpolator>
class MultiDimMapping;


/**
 * @brief Implementation of the MappingIterator-interface which is able
 * to iterate over every value in a MultiDimMapping.
 *
 * As the MultiDimMapping has a tree-like structure of sub-mappings to
 * represent multiple dimensions, the MultiDimIterator consist of a
 * number of sub-MultiDimIterator to represent the current position
 * inside the sub-mappings. So every sub-mapping-iterator represents
 * one dimension and the and Iterator to next Dimensions.
 * The last iterator is an TimeMappingIterator.
 *
 * Iteration works by sub-iterator-first-iteration. Which means that
 * at first the sub-iterator at the current position is iterated to its
 * end before the position inside the dimension of this iterator is increased.
 * This assures the iteration order demanded by the MappingIterator-interface.
 *
 * @author Karl Wessel
 * @ingroup mapping
 */
template<template <typename> class Interpolator>
class MultiDimMappingIterator:public MappingIterator
{
protected:

    /** @brief The templated InterpolateableMap the underlying Mapping uses std::map as storage type.*/
    typedef InterpolateableMap< Interpolator< std::map<argument_value_t, Mapping*> > > interpolator_map_type;

    typedef typename interpolator_map_type::interpolated         interpolated;
    typedef typename interpolator_map_type::iterator_intpl       iterator;
    typedef typename interpolator_map_type::const_iterator_intpl const_iterator;

    /** @brief The MultiDimmapping to iterate over.*/
    const MultiDimMapping<Interpolator>& mapping;

    /** @brief Iterator storing the current position inside the underlying Mappings
     * sub-mapping map.*/
    iterator                             valueIt;

    /** @brief The sub-mapping of the sub-mapping map at the current position.*/
    interpolated                         subMapping;

    /** @brief An iterator for the sub-mapping which points two the current position
     * in the next dimensions.*/
    MappingIterator* subIterator;

    /** @brief The current position in every Dimension of this Iterator.*/
    Argument position;

    /** @brief The position a call to "next()" would jump to.*/
    Argument nextPosition;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & mapping;
        archive & valueIt;
        archive & subMapping;
        archive & subIterator;
        archive & position;
        archive & nextPosition;
    }

protected:

    /**
     * @brief Helper method which updates the sub-iterator for the passed
     * position.
     *
     * Called when the position of of the iterator inside the
     * dimension this Iterator represents has changed.
     */
    void updateSubIterator(const Argument& pos)
    {
        interpolated subM = valueIt.getValue();
        if(subM != subMapping) {
            if(subIterator)
                delete subIterator;

            subMapping = subM;
            if(*subMapping)
                subIterator = (*subMapping)->createIterator(pos);
            else
                subIterator = 0;
        } else {
            if(subIterator)
                subIterator->jumpTo(pos);
        }
    }

    /**
     * @brief Helper method which updates the sub-iterator and sets the position
     * of the sub-iterator to its beginning.
     *
     * Called when the position of of the iterator inside the
     * dimension this Iterator represents has changed.
     */
    void updateSubIterator()
    {
        interpolated subM = valueIt.getValue();
        if(subM != subMapping) {
            if(subIterator)
                delete subIterator;

            subMapping = subM;
            if(*subMapping){
                if(subMapping.isInterpolated)
                    subIterator = (*subMapping)->createIterator(position);
                else
                    subIterator = (*subMapping)->createIterator();
            }else
                subIterator = 0;
        } else {
            if(subIterator)
                subIterator->jumpToBegin();
        }
    }

    /**
     * @brief Helper method which updates the nextPosition member.
     *
     * Called when the current position has changed.
     */
    void updateNextPosition()
    {
        bool intp = subMapping.isInterpolated;

        bool noSubIt = false;
        bool hasNoNext = false;
        if(!intp){
            noSubIt = !subIterator;
            if(!noSubIt)
                hasNoNext = !subIterator->hasNext();
        }
        if(intp || noSubIt || hasNoNext){
            if(valueIt.hasNext()){
                ConstMappingIterator* tmp = (*valueIt.getNextValue())->createConstIterator();
                nextPosition.setArgValues(tmp->getPosition());
                delete tmp;
            }else{
                nextPosition = position;
            }
            nextPosition.setArgValue(mapping.myDimension, valueIt.getNextPosition());

        } else {
            nextPosition.setArgValues(subIterator->getNextPosition());
        }
    }

public:

    /**
     * @brief Initializes the Iterator for the passed MultiDimMapping and sets
     * its position two the first entry of the passed MultiDimMapping.
     */
    MultiDimMappingIterator(MultiDimMapping<Interpolator>& mapping):
        mapping(mapping),
        valueIt(mapping.entries.beginIntpl()),
        subMapping(0), subIterator(0),
        position() {

        subMapping = valueIt.getValue();
        if(!subMapping.isInterpolated && *subMapping) {
            subIterator = (*subMapping)->createIterator();
            position = subIterator->getPosition();
            position.setArgValue(mapping.myDimension, valueIt.getPosition());
        } else {
            position = Argument(mapping.dimensions);
        }
        nextPosition = position;

        updateNextPosition();
    }

    /**
     * @brief Intializes the Iterator for the passed MultiDimMapping and sets
     * its position two the passed position.
     */
    MultiDimMappingIterator(MultiDimMapping<Interpolator>& mapping, const Argument& pos):
        mapping(mapping),
        valueIt(mapping.entries.findIntpl(pos.getArgValue(mapping.myDimension))),
        subMapping(0), subIterator(0),
        position() {

        subMapping = valueIt.getValue();
        if(*subMapping){
            subIterator = (*subMapping)->createIterator(pos);
        }

        position = pos;
        nextPosition = position;
        updateNextPosition();

    }

    /**
     * @brief Frees the memory allocated for the sub mappings.
     */
    virtual ~MultiDimMappingIterator() {
        if(subIterator)
            delete subIterator;
    }

    /**
     * @brief Lets the iterator point to the passed position.
     *
     * The passed new position can be at arbitrary places.
     *
     * Has logarithmic complexity in number of dimensions and number of
     * entries inside each dimension.
     */
    void jumpTo(const Argument& pos){
        argument_value_cref_t argVal = pos.getArgValue(mapping.myDimension);

        if(argVal != valueIt.getPosition() && pos.hasArgVal(mapping.myDimension)) {
            valueIt.jumpTo(argVal);
            updateSubIterator(pos);
        } else {
            if(subIterator)
                subIterator->jumpTo(pos);
        }

        position.setArgValues(pos);
        nextPosition.setArgValues(position);
        updateNextPosition();
    }

    /**
     * @brief Iterates to the specified position. This method
     * should be used if the new position is near the current position.
     *
     * The new position has to be compared bigger than the current position
     *
     * Has linear complexity over the number of entries between the current
     * position and the passed position. This leads to nearly constant
     * complexity for position close together.
     */
    void iterateTo(const Argument& pos){
        argument_value_cref_t argVal = pos.getArgValue(mapping.myDimension);

        if(argVal != valueIt.getPosition() && pos.hasArgVal(mapping.myDimension)) {
            valueIt.iterateTo(argVal);
            updateSubIterator(pos);
        } else {
            if(subIterator)
                subIterator->iterateTo(pos);
        }

        position.setArgValues(pos);
        updateNextPosition();
    }

    /**
     * @brief Iterates to the next position of the function.
     *
     * The next position depends on the implementation of the
     * Function.
     * Calling this method will always work, but if their is no next
     * entry to iterate to inside the underlying Mapping the actual
     * position next jumps will be valid but without meaning.
     * Therefore "hasNext()" should be called before calling this method.
     *
     * Has constant complexity.
     */
    virtual void next(){
        if(!subMapping.isInterpolated && subIterator && subIterator->hasNext()) {
            subIterator->next();
        } else {
            valueIt.next();
            updateSubIterator();
        }


        if(subIterator)
            position.setArgValues(subIterator->getPosition());

        position.setArgValue(mapping.myDimension, valueIt.getPosition());

        updateNextPosition();
    }

    /**
     * @brief Returns true if the current position of the iterator
     * is in range of the function.
     *
     * This method should be used as end-condition when iterating
     * over the function with the "next()" method.
     *
     * Constant complexity.
     */
    virtual bool inRange() const {
        return valueIt.inRange() && (subMapping.isInterpolated || (subIterator && subIterator->inRange()));
    }

    /**
     * @brief Returns the current position of the iterator.
     *
     * Constant complexity.
     */
    virtual const Argument& getPosition() const {
        return position;
    }

    /**
     * @brief returns the next position a call to "next()" would jump to.
     *
     * Constant complexity.
     */
    virtual const Argument& getNextPosition() const {
        return nextPosition;
    }

    /**
     * @brief Returns the value of the underlying mapping at the current
     * position.
     *
     * Has constant complexity.
     */
    virtual argument_value_t getValue() const {
        if(subIterator)
            return subIterator->getValue();
        else
            return Argument::MappedZero();
    }

    /**
     * @brief Lets the iterator point to the begin of the function.
     *
     * The beginning of the function depends is the position of the first
     * entry in the underlying Mapping.
     *
     * Constant complexity.
     */
    virtual void jumpToBegin(){
        valueIt.jumpToBegin();
        updateSubIterator();
        if(subIterator)
            position.setArgValues(subIterator->getPosition());

        position.setArgValue(mapping.myDimension, valueIt.getPosition());
        updateNextPosition();
    }

    /**
     * @brief Returns true if the iterator has a valid next value a call to "next()"
     * could jump to.
     *
     * Constant complexity.
     */
    virtual bool hasNext() const {
        return valueIt.hasNext() || (subIterator && subIterator->hasNext() && valueIt.inRange());
    }

    /**
     * @brief Changes the value of the function at the current
     * position.
     *
     * Constant complexity.
     */
    virtual void setValue(argument_value_cref_t value){
        if(subMapping.isInterpolated) {
            valueIt.setValue(mapping.createSubSignal());
            updateSubIterator(position);
        }
        subIterator->setValue(value);
    }
};



/**
 * @brief Implementation of the Mapping-interface which is able to represent
 * arbitrary dimensional instances of Mappings by using a tree-like structure
 * of sub-mappings, each representing the values for one of the dimensions.
 *
 * This class internally uses a map of Mappings two represent one dimension.
 * Where every Mapping in the map represents a sub-mapping for the values in
 * the next dimension at that position in the this dimension. These sub-mappings
 * can either be in turn MultiDimMappings with further sub-mappings or they can
 * be TimedMappings if their dimension is the time. The TimedMappings therefore
 * represent the leafs of the tree-like structure.
 *
 * @author Karl Wessel
 * @ingroup mapping
 */
template<template <typename> class Interpolator>
class MultiDimMapping:public Mapping
{
protected:

    /** @brief The templated InterpolateableMap the underlying Mapping uses std::map as storage type.*/
    typedef InterpolateableMap< Interpolator< std::map<argument_value_t, Mapping*> > > interpolator_map_type;
    typedef typename interpolator_map_type::interpolator_type    interpolator_type;
    typedef typename interpolator_map_type::mapped_type          mapped_type;
    typedef typename interpolator_map_type::mapped_cref_type     mapped_cref_type;
    typedef typename interpolator_map_type::iterator_intpl       iterator;
    typedef typename interpolator_map_type::const_iterator_intpl const_iterator;

    /**
     * @brief Returned by the Interpolator if the mapping is accessed outside
     * its range (before or after the last key entry in a dimension).
     */
    ConstantSimpleConstMapping* outOfRangeMapping;

    /**
     * @brief Wraps the out of range mapping which is an instance of ConstMapping
     * inside an instance of Mapping which setValue method is asserted to never be called.
     */
    ConstMappingWrapper* wrappedOORMapping;

    /** @brief Stores the sub-mappings for the dimension this instance represents.*/
    interpolator_map_type       entries;

    /** @brief The dimension this instance represents.*/
    Dimension myDimension;

    bool isMaster;

    friend class MultiDimMappingIterator<Interpolator>;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & outOfRangeMapping;
        archive & wrappedOORMapping;
        archive & entries;
        archive & myDimension;
        archive & isMaster;
    }

protected:

    /**
     * @brief Initializes the Mapping with the passed DimensionSet as domain and
     * the passed dimension as the dimension this instance should represent.
     *
     * Also takes the interpolation method to use, but not yet implemented.
     *
     * This constructor is only used internally to create the sub-mappings.
     */
    MultiDimMapping(const DimensionSet& myDims, Dimension myDim):
        Mapping(myDims),
        outOfRangeMapping(0),
        wrappedOORMapping(0),
        entries(),
        myDimension(myDim),
        isMaster(false) {}

    /**
     * @brief Initializes the Mapping with the passed DimensionSet as domain and
     * the passed dimension as the dimension this instance should represent.
     *
     * Also takes the interpolation method to use, but not yet implemented.
     *
     * This constructor is only used internally to create the sub-mappings.
     */
    MultiDimMapping(const DimensionSet& myDims, Dimension myDim,
            ConstantSimpleConstMapping* oorm,
            ConstMappingWrapper* wrappedoorm):
                Mapping(myDims),
                outOfRangeMapping(oorm),
                wrappedOORMapping(wrappedoorm),
                entries(wrappedOORMapping),
                myDimension(myDim),
                isMaster(false) {}

    /**
     * @brief Intern copy-constructor which assures that the sub-mappings are deep
     * copied instead of only their pointers.
     */
    MultiDimMapping(const MultiDimMapping<Interpolator>& o,
            ConstantSimpleConstMapping* oorm,
            ConstMappingWrapper* wrappedoorm):
                Mapping(o),
                outOfRangeMapping(oorm),
                wrappedOORMapping(wrappedoorm),
                entries(o.entries),
                myDimension(o.myDimension),
                isMaster(false){

        entries.setOutOfRangeVal(wrappedOORMapping);

        copySubMappings(o);
    }

    /**
     * @brief Internal helper method which creates a new sub-mapping for this
     * MultiDimMapping instance.
     */
    mapped_type createSubSignal() const{
        const Dimension& nextDim = *(--dimensions.find(myDimension));
        if(wrappedOORMapping == 0) {
            if(nextDim == Dimension::time())
                return new TimeMapping<Interpolator>();
            else
                return new MultiDimMapping<Interpolator>(dimensions, nextDim);
        } else {
            if(nextDim == Dimension::time())
                return new TimeMapping<Interpolator>(outOfRangeMapping->getValue());
            else
                return new MultiDimMapping<Interpolator>(dimensions, nextDim, outOfRangeMapping, wrappedOORMapping);
        }
    }

    void copySubMappings(const MultiDimMapping& o){
        const typename interpolator_map_type::iterator itEnd   = entries.end();
        Dimension                                      nextDim = *(--dimensions.find(myDimension));

        if(nextDim == Dimension::time()) {
            for(typename interpolator_map_type::iterator it = entries.begin(); it != itEnd; ++it) {
                it->second = new TimeMapping<Interpolator>(*(static_cast<TimeMapping<Interpolator>*>(it->second)));
            }
        }
        else {
            for(typename interpolator_map_type::iterator it = entries.begin(); it != itEnd; ++it) {
                if(outOfRangeMapping == 0) {
                    it->second = new MultiDimMapping<Interpolator>(*(static_cast<MultiDimMapping<Interpolator>*>(it->second)));
                } else {
                    it->second = new MultiDimMapping<Interpolator>(*(static_cast<MultiDimMapping<Interpolator>*>(it->second)), outOfRangeMapping, wrappedOORMapping);
                }
            }
        }
    }

public:

    /**
     * @brief Initializes the Mapping with the passed DimensionSet as domain.
     *
     * Also takes the interpolation-method but is not used yet.
     */
    MultiDimMapping(const DimensionSet& myDims):
        Mapping(myDims),
        outOfRangeMapping(0),
        wrappedOORMapping(0),
        entries(),
        isMaster(true){

        myDimension = *(dimensions.rbegin());
    }

    /**
     * @brief Initializes the Mapping with the passed DimensionSet as domain.
     *
     * Also takes the interpolation-method but is not used yet.
     */
    MultiDimMapping(const DimensionSet& myDims, argument_value_cref_t oorv):
        Mapping(myDims),
        outOfRangeMapping(new ConstantSimpleConstMapping(myDims, oorv)),
        wrappedOORMapping(new ConstMappingWrapper(outOfRangeMapping)),
        entries(wrappedOORMapping),
        isMaster(true) {

        myDimension = *(dimensions.rbegin());
    }

    /**
     * @brief Copy-constructor which assures that the sub-mappings are deep
     * copied instead of only their the pointers.
     */
    MultiDimMapping(const MultiDimMapping<Interpolator>& o):
        Mapping(o),
        outOfRangeMapping(o.outOfRangeMapping),
        wrappedOORMapping(o.wrappedOORMapping),
        entries(o.entries),
        myDimension(o.myDimension),
        isMaster(true) {

        if(outOfRangeMapping != 0){
            outOfRangeMapping = new ConstantSimpleConstMapping(dimensions, o.outOfRangeMapping->getValue());
            wrappedOORMapping = new ConstMappingWrapper(outOfRangeMapping);
            entries.setOutOfRangeVal(wrappedOORMapping);
        }
        copySubMappings(o);
    }

    /**
     * @brief Copy operator which assures that the sub-mappings are deep
     * copied instead of only their the pointers.
     */
    const MultiDimMapping& operator=(const MultiDimMapping<Interpolator>& o){
        const typename interpolator_map_type::const_iterator itEnd = entries.end();
        for(typename interpolator_map_type::const_iterator it = entries.begin(); it != itEnd; ++it) {
            if(it->second)
                delete it->second;
        }

        dimensions        = o.dimensions;
        entries           = o.entries;
        myDimension       = o.myDimension;
        outOfRangeMapping = o.outOfRangeMapping;
        wrappedOORMapping = o.wrappedOORMapping;
        isMaster          = true;

        if(outOfRangeMapping != 0){
            outOfRangeMapping = new ConstantSimpleConstMapping(dimensions, o.outOfRangeMapping->getValue());
            wrappedOORMapping = new ConstMappingWrapper(outOfRangeMapping);
            entries.setOutOfRangeVal(wrappedOORMapping);
        }

        copySubMappings(o);

        return *this;
    }

    /**
     * @brief returns a deep copy of this mapping instance.
     */
    virtual Mapping* clone() const { return new MultiDimMapping<Interpolator>(*this); }

    /**
     * @brief Frees the memory for the sub mappings.
     */
    virtual ~MultiDimMapping() {
        const typename interpolator_map_type::const_iterator itEnd = entries.end();
        for(typename interpolator_map_type::const_iterator it = entries.begin(); it != itEnd; ++it) {
            if (it->second)
                delete it->second;
        }

        if(isMaster) {
            if(outOfRangeMapping)
                delete outOfRangeMapping;
            if(wrappedOORMapping)
                delete wrappedOORMapping;
        }
    }

    /**
     * @brief Returns the value of this Mapping at position specified
     * by the passed Argument.
     *
     * Has logarithmic complexity over the number of dimensions and the number of
     * entries per dimension.
     */
    virtual argument_value_t getValue(const Argument& pos) const {
        assert(pos.hasArgVal(myDimension));
        argument_value_cref_t                        argVal = pos.getArgValue(myDimension);
        typename interpolator_map_type::interpolated subM   = entries.getIntplValue(argVal);

        if(!(*subM))
            return Argument::MappedZero();

        return (*subM)->getValue(pos);
    }

    /**
     * @brief Changes the value of the Mapping at the specified
     * position.
     *
     * Has logarithmic complexity over the number of dimensions and the number of
     * entries per dimension.
     */
    virtual void setValue(const Argument& pos, argument_value_cref_t value) {
        argument_value_cref_t                    argVal = pos.getArgValue(myDimension);
        typename interpolator_map_type::iterator posIt  = entries.lower_bound(argVal);

        if(posIt == entries.end() || (entries.key_comp()(argVal, posIt->first))) {
            posIt = entries.insert(posIt, std::make_pair(argVal, createSubSignal()));
        }
        posIt->second->setValue(pos, value);
    }

    /**
     * @brief Returns a pointer of a new Iterator which is able to iterate
     * over the Mapping and can change the value the iterator points to.
     *
     * The caller of this method has to delete the Iterator if not needed
     * anymore.
     */
    virtual MappingIterator* createIterator() {
        return new MultiDimMappingIterator<Interpolator>(*this);
    }

    /**
     * @brief Returns a pointer of a new Iterator which is able to iterate
     * over the Mapping and can change the value the iterator points to.
     *
     * The caller of this method has to delete the Iterator if not needed
     * anymore.
     */
    virtual MappingIterator* createIterator(const Argument& pos) {
        return new MultiDimMappingIterator<Interpolator>(*this, pos);
    }


    /**
     * @brief Returns the dimension this instance represents.
     */
    Dimension getDimension() { return myDimension; }
};


/**
 * @brief MappingIterator implementation for FilledUpMappings.
 *
 * Assures that although FilledUpMapping is an Mapping instance the
 * "setValue()"-method may never be called.
 *
 * @sa FilledUpMapping
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
class MIXIM_API FilledUpMappingIterator : public MultiDimMappingIterator<Linear>
{
public:

    FilledUpMappingIterator(FilledUpMapping& mapping);

    FilledUpMappingIterator(FilledUpMapping& mapping, const Argument& pos);

    virtual void setValue(argument_value_cref_t value) {
        assert(false);
    }
};


/**
 * @brief Takes a source ConstMapping with a domain A and a set of KeyEntries
 * for a domain B and creates a clone of the source mapping with the domain B
 * and the KeyEntries passed.
 *
 * This class is used by "applyElementWiseOperator()"-method to be able
 * to handle cases where the second mappings domain is a real subset of
 * the first mappings domain (meaning the first mappings domain has the same
 * dimensions as the seconds domain and at least one further dimension).
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
class MIXIM_API FilledUpMapping : public MultiDimMapping<Linear>
{
public:

    typedef std::set<argument_value_t>   KeySet;
    typedef std::map<Dimension, KeySet > KeyMap;

protected:

    Mapping*      fillRef;
    const KeyMap& keys;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & fillRef;
        archive & keys;
    }

protected:

    void fillRefIfNecessary()
    {
        const KeyMap::const_iterator itEnd = keys.end();
        KeyMap::const_iterator       it    = keys.find(myDimension);

        if(it == itEnd)
            return;

        fillRef = createSubSignal();

        const KeySet::const_iterator keyItEnd = it->second.end();
        for (KeySet::const_iterator keyIt = it->second.begin(); keyIt != keyItEnd; ++keyIt) {
            entries.insert(entries.end(), std::make_pair(*keyIt, fillRef));
        }
    }

    FilledUpMapping(const DimensionSet& myDims, Dimension myDim, const KeyMap& rkeys):
        MultiDimMapping<Linear>(myDims, myDim), fillRef(0), keys(rkeys)
        {
        fillRefIfNecessary();
        }

    Mapping* createSubSignal() const{
        const Dimension& nextDim = *(--dimensions.find(myDimension));
        if(nextDim == Dimension::time())
            return MultiDimMapping<Linear>::createSubSignal();
        else
            return new FilledUpMapping(dimensions, nextDim, keys);
    }

public:

    FilledUpMapping(const ConstMapping* source, const DimensionSet& dims, const KeyMap& rkeys):
        MultiDimMapping<Linear>(dims), fillRef(0), keys(rkeys)
        {
        ConstMappingIterator* it = source->createConstIterator();

        if(it->inRange()) {
            fillRefIfNecessary();

            while(it->inRange()) {
                appendValue(it->getPosition(), it->getValue());

                if(!it->hasNext())
                    break;
                it->next();
            }
        }
        delete it;
        }

    virtual ~FilledUpMapping(){
        if(fillRef != 0){
            delete fillRef;
            entries.clear();
        }
    }

    virtual void appendValue(const Argument& pos, argument_value_cref_t value) {
        if(fillRef != 0) {
            fillRef->appendValue(pos, value);
            return;
        }
        argument_value_cref_t                    argVal = pos.getArgValue(myDimension);
        interpolator_map_type::iterator posIt  = entries.lower_bound(argVal);

        if(posIt == entries.end() || (entries.key_comp()(argVal, posIt->first))) {
            posIt = entries.insert(posIt, std::make_pair(argVal, createSubSignal()));
        }
        posIt->second->appendValue(pos, value);
    }

    virtual MappingIterator* createIterator() {
        return new FilledUpMappingIterator(*this);
    }

    virtual MappingIterator* createIterator(const Argument& pos) {
        return new FilledUpMappingIterator(*this, pos);
    }
};


/**
 * @brief Provides several utility methods for Mappings.
 *
 * @author Karl Wessel
 * @ingroup mapping
 */
class MIXIM_API MappingUtils
{
public:

    typedef std::list<const ConstMapping*> MappingBuffer;

    /** @brief The default value for findMin() functions if it does not find a minimum element.
     *
     * It will be initialized with the infinity value.
     */
    const static Argument::mapped_type cMinNotFound() {
        return std::numeric_limits<Argument::mapped_type>::infinity();
    }

    /** @brief The default value for findMax() functions if it does not find a maximum element.
     *
     * It will be initialized with the negative infinity value.
     */
    const static Argument::mapped_type cMaxNotFound() {
        return -std::numeric_limits<Argument::mapped_type>::infinity();
    }

private:

    static const ConstMapping *const createCompatibleMapping(const ConstMapping& src, const ConstMapping& dst);

    static bool iterateToNext(ConstMappingIterator* it1, ConstMappingIterator* it2);

public:

    /**
     * @brief Returns an appropriate changeable Mapping with the specified domain
     * and the specified interpolation method.
     *
     * Note: The interpolation method is always linear, at the moment.
     */
    static Mapping* createMapping(const DimensionSet& domain = DimensionSet(Dimension::time()),
            Mapping::InterpolationMethod intpl = Mapping::LINEAR);

    /**
     * @brief Returns an appropriate changeable Mapping with the specified domain
     * and the specified interpolation method.
     *
     * Note: The interpolation method is always linear, at the moment.
     */
    static Mapping* createMapping(Mapping::argument_value_cref_t outOfRangeValue,
            const DimensionSet& domain = DimensionSet(Dimension::time()),
            Mapping::InterpolationMethod intpl = Mapping::LINEAR);

    template<class Operator>
    static Mapping* applyElementWiseOperator(const ConstMapping& f1, const ConstMapping& f2,
            const Argument& intvlStart,
            const Argument& intvlEnd,
            Operator op){

        return 0;
    }

    template<class Operator>
    static Mapping* applyElementWiseOperator(const ConstMapping& f1, const ConstMapping& f2, Operator op,
            Mapping::argument_value_cref_t outOfRangeVal  = Argument::MappedZero(),
            bool                           contOutOfRange = true) {

        using std::operator<<;

        const ConstMapping *const f2Comp = createCompatibleMapping(f2, f1);
        const ConstMapping *const f1Comp = createCompatibleMapping(f1, f2);

        const DimensionSet& domain = f1Comp->getDimensionSet();
        Mapping *const      result = (contOutOfRange) ? MappingUtils::createMapping(domain) : MappingUtils::createMapping(outOfRangeVal, domain);

        ConstMappingIterator *const itF1       = f1Comp->createConstIterator();
        ConstMappingIterator *const itF2       = f2Comp->createConstIterator();
        const bool                  bF1InRange = itF1->inRange();
        const bool                  bF2InRange = itF2->inRange();

        if(!bF1InRange && !bF2InRange){
            delete itF1;
            delete itF2;
            return result;
        }

        MappingIterator* itRes = 0;

        if(bF1InRange && (!bF2InRange || itF1->getPosition() < itF2->getPosition())){
            itF2->jumpTo(itF1->getPosition());
        } else {
            itF1->jumpTo(itF2->getPosition());
        }

        itRes = result->createIterator(itF1->getPosition());

        while(itF1->inRange() || itF2->inRange()) {
            assert(itF1->getPosition().isSamePosition(itF2->getPosition()));

            Mapping::argument_value_cref_t prod = op(itF1->getValue(), itF2->getValue());
            //result->setValue(itF1->getPosition(), prod);
            itRes->setValue(prod);

            if(!iterateToNext(itF1, itF2))
                break;

            itRes->iterateTo(itF1->getPosition());
        }

        delete itF1;
        delete itF2;
        delete itRes;

        if (&f2 != f2Comp)
            delete (f2Comp);
        if (&f1 != f1Comp)
            delete (f1Comp);

        return result;
    }

    /**
     * @brief Multiplies the passed functions element-wise with each other
     * and returns the result in a new Function.
     *
     * The domain (DimensionSet) of the result is defined by the domain
     * of the first operand.
     * The domain of the second Mapping has to be a subset of the domain of
     * the first mapping.
     */
    static Mapping* multiply(const ConstMapping& f1, const ConstMapping& f2);
    static Mapping* add(const ConstMapping& f1, const ConstMapping& f2);
    static Mapping* subtract(const ConstMapping& f1, const ConstMapping& f2);
    static Mapping* divide(const ConstMapping& f1, const ConstMapping& f2);

    static Mapping* multiply(const ConstMapping& f1, const ConstMapping& f2, Mapping::argument_value_cref_t outOfRangeVal);
    static Mapping* add(const ConstMapping& f1, const ConstMapping& f2, Mapping::argument_value_cref_t outOfRangeVal);
    static Mapping* subtract(const ConstMapping& f1, const ConstMapping& f2, Mapping::argument_value_cref_t outOfRangeVal);
    static Mapping* divide(const ConstMapping& f1, const ConstMapping& f2, Mapping::argument_value_cref_t outOfRangeVal);

    /**
     * @brief Iterates over the passed mapping and returns value at the key entry
     * with the highest value.
     *
     * @param m            The map where the maximum value shall be searched.
     * @param cRetNotFound The value which shall be returned if no maximum was found (default MappingUtils::cMaxNotFound).
     * @return The value at the key entry with the highest value or <tt>cRetNotFound</tt> if map is empty.
     */
    static Argument::mapped_type findMax(const ConstMapping& m, Argument::mapped_type_cref cRetNotFound = cMaxNotFound());

    /**
     * @brief Iterates over the passed mapping and returns the value at the key
     * entry with the highest value in the range defined by the passed min and
     * max parameter.
     *
     * The area defined by the min and max parameter is the number of key entries
     * which position in each dimension is bigger or equal than the value of the min
     * parameter in that dimension and smaller or equal than max parameter in
     * that dimension.
     *
     * @param m            The map where the maximum value shall be searched.
     * @param min          The beginning of search range.
     * @param max          The end of search range.
     * @param cRetNotFound The value which shall be returned if no maximum was found (default MappingUtils::cMaxNotFound).
     * @return The value at the key entry with the highest value or <tt>cRetNotFound</tt> if map is empty or no element in range [min,max].
     */
    static Argument::mapped_type findMax(const ConstMapping& m, const Argument& min, const Argument& max, Argument::mapped_type_cref cRetNotFound = cMaxNotFound());

    /**
     * @brief Iterates over the passed mapping and returns value at the key entry
     * with the smallest value.
     *
     * @param m            The map where the minimum value shall be searched.
     * @param cRetNotFound The value which shall be returned if no minimum was found (default MappingUtils::cMinNotFound).
     * @return The value at the key entry with the lowest value or <tt>cRetNotFound</tt> if map is empty.
     */
    static Argument::mapped_type findMin(const ConstMapping& m, Argument::mapped_type_cref cRetNotFound = cMinNotFound());

    /**
     * @brief Iterates over the passed mapping and returns the value at the key
     * entry with the smallest value in the range defined by the passed min and
     * max parameter.
     *
     * The area defined by the min and max parameter is the number of key entries
     * which position in each dimension is bigger or equal than the value of the min
     * parameter in that dimension and smaller or equal than max parameter in
     * that dimension.
     *
     * @param m            The map where the minimum value shall be searched.
     * @param min          The beginning of search range.
     * @param max          The end of search range.
     * @param cRetNotFound The value which shall be returned if no minimum was found (default MappingUtils::cMinNotFound).
     * @return The value at the key entry with the highest value or <tt>cRetNotFound</tt> if map is empty or no element in range [min,max].
     */
    static Argument::mapped_type findMin(const ConstMapping& m, const Argument& min, const Argument& max, Argument::mapped_type_cref cRetNotFound = cMinNotFound());


    /*
	static Mapping* multiply(ConstMapping& f1, ConstMapping& f2, const Argument& from, const Argument& to);
	static Mapping* add(ConstMapping& f1, ConstMapping& f2, const Argument& from, const Argument& to);
	static Mapping* subtract(ConstMapping& f1, ConstMapping& f2, const Argument& from, const Argument& to);
	static Mapping* divide(ConstMapping& f1, ConstMapping& f2, const Argument& from, const Argument& to);
     */


    /**
     * @brief Adds a discontinuity in time-dimension, i.e. its representation, to a passed mapping.
     *
     * This is done by setting a regular entry and a limit-entry. The limit-entry shall be
     * very close to the regular entry (on its left or right).
     *
     * The implementation works simply by adding the limit-value as a separate entry at the
     * position of the limit-time. This means that this methods adds a total of two entries
     * to the passed mapping.
     *
     * Note: One should use the methods 'pre' or 'post' provided by MappingUtils to calculate
     * the limit-time for the discontinuity.
     *
     * @param m The mapping the discontinuity will be added to.
     * @param pos The position of the regular entry.
     * @param value The value of the regular entry.
     * @param limitTime The time-point of the limit-entry.
     * @param limitValue The value of the limit-entry.
     *
     */
    static void addDiscontinuity(Mapping* m,
            const Argument& pos, Argument::mapped_type_cref value,
            omnetpp::simtime_t_cref limitTime, Argument::mapped_type_cref limitValue);

    /**
     * @brief returns the closest value of simtime before passed value
     */
    static omnetpp::simtime_t pre(omnetpp::simtime_t_cref t);

    /**
     * @brief returns the closest value of simtime after passed values
     */
    static omnetpp::simtime_t post(omnetpp::simtime_t_cref t);
};


/**
 * @brief Deletes its ConstMapping when this iterator is deleted.
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
class MIXIM_API ConcatConstMappingIterator : public FilteredConstMappingIterator
{
protected:

    ConstMapping* baseMapping;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & baseMapping;
    }

public:

    ConcatConstMappingIterator(ConstMapping* baseMapping):
        FilteredConstMappingIterator(baseMapping->createConstIterator()),
        baseMapping(baseMapping) {}

    ConcatConstMappingIterator(ConstMapping* baseMapping, const Argument& pos):
        FilteredConstMappingIterator(baseMapping->createConstIterator(pos)),
        baseMapping(baseMapping) {}

    virtual ~ConcatConstMappingIterator() {
        delete baseMapping;
    }
};


/**
 * @brief Defines it values by concatenating one or more
 * Mappings to a reference Mapping.
 *
 * @author Karl Wessel
 * @ingroup mappingDetails
 */
template<class Operator>
class ConcatConstMapping: public ConstMapping
{
protected:

    typedef std::pair<Dimension, Argument::const_iterator> DimIteratorPair;
    typedef std::list<ConstMapping*> MappingSet;
    MappingSet            mappings;
    ConstMapping*         refMapping;

    bool                  continueOutOfRange;
    Argument::mapped_type oorValue;

    Operator op;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & mappings;
        archive & refMapping;
        archive & continueOutOfRange;
        archive & oorValue;
    }

public:

    /**
     * @brief Initializes with the passed reference Mapping, the operator
     * and the Mappings defined by the passed iterator.
     */
    template<class Iterator>
    ConcatConstMapping(ConstMapping* refMapping,
            Iterator first, Iterator last,
            bool continueOutOfRange = true,
            Argument::mapped_type_cref oorValue = Argument::mapped_type(0),
            Operator op = Operator()):
            ConstMapping(refMapping->getDimensionSet()),
            refMapping(refMapping),
            continueOutOfRange(continueOutOfRange),
            oorValue(oorValue),
            op(op)
            {
        while(first != last) {
            mappings.push_back(*first);
            ++first;
        }
            }

    /**
     * @brief Initializes with the passed reference Mapping, the operator
     * and another Mapping to concatenate.
     */
    ConcatConstMapping(ConstMapping* refMapping, ConstMapping* other,
            bool continueOutOfRange = true,
            Argument::mapped_type_cref oorValue = Argument::mapped_type(0),
            Operator op = Operator()):
                ConstMapping(refMapping->getDimensionSet()),
                refMapping(refMapping),
                continueOutOfRange(continueOutOfRange),
                oorValue(oorValue),
                op(op)
    {
        mappings.push_back(other);
    }

    /**
     * @brief Adds another Mapping to the list of Mappings to
     * concatenate.
     */
    void addMapping(ConstMapping* m) {
        mappings.push_back(m);
    }

    virtual Argument::mapped_type getValue(const Argument& pos) const {
        const MappingSet::const_iterator itEnd = mappings.end();
        Argument::mapped_type            res   = refMapping->getValue(pos);

        for (MappingSet::const_iterator it = mappings.begin(); it != itEnd; ++it) {
            res = op(res, (*it)->getValue(pos));
        }

        return res;
    }

    /**
     * @brief Returns the concatenated Mapping.
     */
    Mapping* createConcatenatedMapping() const {
        assert(!mappings.empty());

        MappingSet::const_iterator       it    = mappings.begin();
        const MappingSet::const_iterator itEnd = mappings.end();

        Mapping* result = MappingUtils::applyElementWiseOperator(*refMapping, **it, op,
                oorValue, continueOutOfRange);

        while(++it != itEnd) {
            Mapping* buf = result;
            result = MappingUtils::applyElementWiseOperator(*buf, **it, op,
                    oorValue, continueOutOfRange);
            delete buf;
        }

        return result;
    }

    virtual ConstMappingIterator* createConstIterator() const {
        if(mappings.empty()) {
            return refMapping->createConstIterator();
        }
        return new ConcatConstMappingIterator(createConcatenatedMapping());
    }

    virtual ConstMappingIterator* createConstIterator(const Argument& pos) const {
        if(mappings.empty()) {
            return refMapping->createConstIterator(pos);
        }
        return new ConcatConstMappingIterator(createConcatenatedMapping(), pos);
    }

    virtual ConstMapping* constClone() const {
        return new ConcatConstMapping(*this);
    }

    /**
     * @brief Returns the pointer to the reference mapping.
     */
    ConstMapping* getRefMapping() {
        return refMapping;
    }
};


/**
 * @brief Common base for a Const- and NonConst-Iterator for a DelayedMapping.
 *
 * @sa BaseDelayedMapping
 * @ingroup mappingDetails
 * @author Karl Wessel
 */
template<class Base, class Iterator>
class BaseDelayedIterator: public Base
{
protected:

    omnetpp::simtime_t delay;

    Argument position;
    Argument nextPosition;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & delay;
        archive & position;
        archive & nextPosition;
    }

protected:

    Argument undelayPosition(const Argument& pos) const{
        Argument res(pos);
        res.setTime(res.getTime() - delay);
        return res;
    }

    Argument delayPosition(const Argument& pos) const {
        Argument res(pos);
        res.setTime(res.getTime() + delay);
        return res;
    }

    void updatePosition() {
        nextPosition = delayPosition(this->origIterator->getNextPosition());
        position = delayPosition(this->origIterator->getPosition());
    }

public:

    BaseDelayedIterator(Iterator* it, omnetpp::simtime_t_cref delay):
        Base(it), delay(delay) {

        updatePosition();
    }

    virtual ~BaseDelayedIterator() {}

    virtual const Argument& getNextPosition() const { return nextPosition; }

    virtual void jumpTo(const Argument& pos) {
        this->origIterator->jumpTo(undelayPosition(pos));
        updatePosition();
    }

    virtual void jumpToBegin() {
        this->origIterator->jumpToBegin();
        updatePosition();
    }

    virtual void iterateTo(const Argument& pos) {
        this->origIterator->iterateTo(undelayPosition(pos));
        updatePosition();
    }

    virtual void next() {
        this->origIterator->next();
        updatePosition();
    }

    virtual const Argument& getPosition() const {
        return position;
    }
};


/**
 * @brief ConstIterator for a ConstDelayedMapping
 *
 * @sa ConstDelayedMapping
 * @ingroup mappingDetails
 * @author Karl Wess
 */
typedef BaseDelayedIterator<FilteredConstMappingIterator, ConstMappingIterator> ConstDelayedMappingIterator;

/**
 * @brief Iterator for a DelayedMapping.
 *
 * @sa DelayedMapping
 * @ingroup mappingDetails
 * @author Karl Wessel
 */
typedef BaseDelayedIterator<FilteredMappingIterator, MappingIterator> DelayedMappingIterator;

/**
 * @brief Common base for Const- and NonConst-DelayedMapping.
 *
 * @sa DelayedMapping, ConstDelayedMapping
 * @ingroup mappingDetails
 * @author Karl Wessel
 */
template<class Base>
class BaseDelayedMapping: public Base
{
protected:

    Base* mapping;
    omnetpp::simtime_t delay;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & mapping;
        archive & delay;
    }

protected:

    Argument delayPosition(const Argument& pos) const
    {
        Argument res(pos);
        res.setTime(res.getTime() - delay);
        return res;
    }

public:

    BaseDelayedMapping(Base* mapping, omnetpp::simtime_t_cref delay):
        Base(mapping->getDimensionSet()), mapping(mapping), delay(delay) {}

    virtual ~BaseDelayedMapping() {}

    virtual typename Base::argument_value_t getValue(const Argument& pos) const {
        return mapping->getValue(delayPosition(pos));
    }

    virtual ConstMappingIterator* createConstIterator() const {
        return new ConstDelayedMappingIterator(mapping->createConstIterator(), delay);
    }

    virtual ConstMappingIterator* createConstIterator(const Argument& pos) const {
        return new ConstDelayedMappingIterator(mapping->createConstIterator(delayPosition(pos)), delay);
    }

    /**
     * @brief Returns the delay used by this mapping.
     */
    virtual omnetpp::simtime_t_cref getDelay() const {
        return delay;
    }

    /**
     * @brief Changes the delay to the passed value.
     */
    virtual void delayMapping(omnetpp::simtime_t_cref d) {
        delay = d;
    }
};


/**
 * @brief Moves another ConstMapping in its time dimension.
 *
 * See propagation delay effect of the signal for an example
 * how to use this mapping.
 *
 * @ingroup mappingDetails
 * @author Karl Wessel
 */
class MIXIM_API ConstDelayedMapping: public BaseDelayedMapping<ConstMapping>
{
public:

    ConstDelayedMapping(ConstMapping* mapping, omnetpp::simtime_t_cref delay):
        BaseDelayedMapping<ConstMapping>(mapping, delay) {}

    virtual ~ConstDelayedMapping() {}

    virtual ConstMapping* constClone() const {
        return new ConstDelayedMapping(mapping->constClone(), delay);
    }
};


/**
 * @brief Moves another Mapping in its time dimension.
 *
 * See propagation delay effect of the signal for an example
 * how to use this mapping.
 *
 * @ingroup mappingDetails
 * @author Karl Wessel
 */
class MIXIM_API DelayedMapping: public BaseDelayedMapping<Mapping>
{
public:

    DelayedMapping(Mapping* mapping, omnetpp::simtime_t_cref delay):
        BaseDelayedMapping<Mapping>(mapping, delay) {}

    virtual ~DelayedMapping() {}

    virtual void setValue(const Argument& pos, Argument::mapped_type_cref value) {
        mapping->setValue(delayPosition(pos), value);
    }

    virtual Mapping* clone() const {
        return new DelayedMapping(mapping->clone(), delay);
    }

    virtual MappingIterator* createIterator() {
        return new DelayedMappingIterator(mapping->createIterator(), delay);
    }

    virtual MappingIterator* createIterator(const Argument& pos) {
        return new DelayedMappingIterator(mapping->createIterator(delayPosition(pos)), delay);
    }
};


MIXIM_API Mapping* operator*(const ConstMapping& f1, const ConstMapping& f2);
MIXIM_API Mapping* operator/(const ConstMapping& f1, const ConstMapping& f2);
MIXIM_API Mapping* operator+(const ConstMapping& f1, const ConstMapping& f2);
MIXIM_API Mapping* operator-(const ConstMapping& f1, const ConstMapping& f2);

#endif /* SIGNALINTERFACES_H_ */
